TBitmap a TMemoryStream - was: Predavani obrazku (TBitmap) pres COM/DCOM

Otázka od: Libor Filip

12. 11. 2002 11:53

         COM/DCOM
Delka toho streamu je v poradku.
Problem je pri nacitani ze streamu.
Tento jednoduchy kod nenacte bitmapu ze streamu.
Kde je problem?

var
  TempStream:TMemoryStream;
  bmp: TBitmap;
begin
  TempStream:=TMemoryStream.Create;
  bmp := TBitmap.Create;

  Logo.SaveToFile('c:\a1.bmp'); //na disku ulozena bitmapa je v poradku
  Logo.SaveToStream(TempStream);
  bmp.LoadFromStream(TempStream);
  bmp.SaveToFile('c:\a2.bmp'); //soubor ma nulovou delku

  TempStream.Free;
  bmp.Free;
end

Libor

-----Original Message-----
From: delphi-l-owner@clexpert.cz [mailto:delphi-l-owner@clexpert.cz]On
Behalf Of Richard Kejval
Sent: Tuesday, November 12, 2002 10:43 AM
To: delphi-l@clexpert.cz
Subject: Re: Predavani obrazku (TBitmap) pres COM/DCOM


No nevim, co ta delka toho streamu je v poradku ? Zkusil bych to mozna
prvne ulozit na disk pres filestream, prohlidnout a pak teprve nacist,
protoze nacist buffer ze streamu, kdyz znam jeho velikost, by nemel byt
problem a tuto konstrukci bezne pouzivam.

S pozdravem
ing. Richard Kejval
IC Software s.r.o
Mobil: +420602477679

Odpovedá: Ondrej Kelle

12. 11. 2002 12:32

         COM/DCOM
> Delka toho streamu je v poradku.
> Problem je pri nacitani ze streamu.
> Tento jednoduchy kod nenacte bitmapu ze streamu.
> Kde je problem?
>
> var
> TempStream:TMemoryStream;
> bmp: TBitmap;
> begin
> TempStream:=TMemoryStream.Create;
> bmp := TBitmap.Create;
>
> Logo.SaveToFile('c:\a1.bmp'); //na disku ulozena bitmapa je
> v poradku

Po vykonani SaveToFile je pozicia streamu na konci, takze nasledovne volanie
SaveToStream neuchova nic  

> Logo.SaveToStream(TempStream);
> bmp.LoadFromStream(TempStream);
> bmp.SaveToFile('c:\a2.bmp'); //soubor ma nulovou delku
>
> TempStream.Free;
> bmp.Free;
> end

HTH
TOndrej

Odpovedá: Libor Filip

12. 11. 2002 13:47

         COM/DCOM
To mi vysvetli. Logo je typu TBitmap. A tim kodem chci
zkopirovat bitmapu z Logo do bmp.

var
  TempStream:TMemoryStream;
  bmp: TBitmap;
begin
  TempStream:=TMemoryStream.Create;
  bmp := TBitmap.Create;
                                //Logo: TBitmap
  Logo.SaveToFile('c:\a1.bmp'); //na disku ulozena bitmapa je v poradku
  Logo.SaveToStream(TempStream);
  bmp.LoadFromStream(TempStream);
  bmp.SaveToFile('c:\a2.bmp'); //soubor ma nulovou delku

  TempStream.Free;
  bmp.Free;
end

Libor
-----Original Message-----
From: delphi-l-owner@clexpert.cz [mailto:delphi-l-owner@clexpert.cz]On
Behalf Of Ondrej Kelle
Sent: Tuesday, November 12, 2002 11:33 AM
To: 'delphi-l@clexpert.cz'
Subject: RE: TBitmap a TMemoryStream - was: Predavani obrazku (TBitmap)
pres COM/DCOM


> Delka toho streamu je v poradku.
> Problem je pri nacitani ze streamu.
> Tento jednoduchy kod nenacte bitmapu ze streamu.
> Kde je problem?
>
> var
> TempStream:TMemoryStream;
> bmp: TBitmap;
> begin
> TempStream:=TMemoryStream.Create;
> bmp := TBitmap.Create;
>
> Logo.SaveToFile('c:\a1.bmp'); //na disku ulozena bitmapa je
> v poradku

Po vykonani SaveToFile je pozicia streamu na konci, takze nasledovne volanie
SaveToStream neuchova nic  

HTH
TOndrej

Odpovedá: ing. Jan Fiala

12. 11. 2002 13:11

         COM/DCOM
TOnder tim chtel rict, ze musis po LoadFromStream nastavit
Position := 0;
a pak teprve provest SaveToStream

--
ing. Jan Fiala
mailto:jan.fiala@iol.cz

12.11.2002 Libor Filip:
> To mi vysvetli. Logo je typu TBitmap. A tim kodem chci
> zkopirovat bitmapu z Logo do bmp.

> var
> TempStream:TMemoryStream;
> bmp: TBitmap;
> begin
> TempStream:=TMemoryStream.Create;
> bmp := TBitmap.Create;
> //Logo: TBitmap
> Logo.SaveToFile('c:\a1.bmp'); //na disku ulozena bitmapa je v poradku
> Logo.SaveToStream(TempStream);
> bmp.LoadFromStream(TempStream);
> bmp.SaveToFile('c:\a2.bmp'); //soubor ma nulovou delku

> TempStream.Free;
> bmp.Free;
> end

>> Po vykonani SaveToFile je pozicia streamu na konci, takze nasledovne volanie
>> SaveToStream neuchova nic  
>> TOndrej

Odpovedá: Ondrej Kelle

12. 11. 2002 12:55

         COM/DCOM
> TOnder tim chtel rict, ze musis po LoadFromStream nastavit
> Position := 0;
> a pak teprve provest SaveToStream

Presne tak, ospravedlnujem sa, opet som cital velmi rychlo a nepozorne.

Logo.SaveToStream(TempStream);
- to nastavi poziciu TempStream na koniec. Takze pred LoadFromStream ju
potrebujes nastavit spet na zaciatok:

TempStream.Position := 0; alebo TempStream.Seek(0, soFromBeginning);
bmp.LoadFromStream(TempStream);

V praxi je to aj u mna dost bezna chyba pri praci so streamami.  

HTH
TOndrej

Odpovedá: Libor Filip

12. 11. 2002 15:11

         COM/DCOM
Stale mi to neni jasne. Posilam to jeste jednou z komentarem, co delam.

var
  TempStream:TMemoryStream;
  bmp: TBitmap;
begin
  TempStream:=TMemoryStream.Create;
  bmp := TBitmap.Create;

  //z TBitmap provedu ulozeni na disk
                                //Logo: TBitmap
  Logo.SaveToFile('c:\a1.bmp'); //na disku ulozena bitmapa je v poradku
  //z TBitmap ulozim do streamu
  Logo.SaveToStream(TempStream);
  //ze streamu nahraju do TBitmap; jestli je predtim TempStream.Position :=
0 neni rozhodujici
  bmp.LoadFromStream(TempStream);
  //z TBitmap provedu ulozeni na disk
  bmp.SaveToFile('c:\a2.bmp'); //soubor ma nulovou delku

  TempStream.Free;
  bmp.Free;
end

Libor

-----Original Message-----
From: delphi-l-owner@clexpert.cz [mailto:delphi-l-owner@clexpert.cz]On
Behalf Of ing. Jan Fiala
Sent: Tuesday, November 12, 2002 12:40 PM
To: delphi-l@clexpert.cz
Subject: Re: TBitmap a TMemoryStream - was: Predavani obrazku (TBitmap) pres
COM/DCOM


TOnder tim chtel rict, ze musis po LoadFromStream nastavit
Position := 0;
a pak teprve provest SaveToStream

--
ing. Jan Fiala
mailto:jan.fiala@iol.cz

Odpovedá: Alexandr Stefek

14. 11. 2002 8:18

         COM/DCOM
> Logo.SaveToFile('c:\a1.bmp'); //na disku ulozena bitmapa je v poradku
> //z TBitmap ulozim do streamu
> Logo.SaveToStream(TempStream);
> //ze streamu nahraju do TBitmap; jestli je predtim TempStream.Position
:=
> 0 neni rozhodujici

//no to teda je rozhodujici
    TempStream.Seek(0, soFromBeginning);

> bmp.LoadFromStream(TempStream);
> //z TBitmap provedu ulozeni na disk
> bmp.SaveToFile('c:\a2.bmp'); //soubor ma nulovou delku
>
> TempStream.Free;
> bmp.Free;
> end
>
> Libor

Odpovedá: Libor Filip

14. 11. 2002 9:28

         COM/DCOM
Kez by to rozhodujici bylo. Stale mi to neslape.
a2.bmp ma nulovou delku. Nemusi se jeste nejak nastavit objekt bmp?

Libor, D5 Ent. Upd 1


> Logo.SaveToFile('c:\a1.bmp'); //na disku ulozena bitmapa je v poradku
> //z TBitmap ulozim do streamu
> Logo.SaveToStream(TempStream);
> //ze streamu nahraju do TBitmap; jestli je predtim TempStream.Position
:=
> 0 neni rozhodujici

//no to teda je rozhodujici
    TempStream.Seek(0, soFromBeginning);

> bmp.LoadFromStream(TempStream);
> //z TBitmap provedu ulozeni na disk
> bmp.SaveToFile('c:\a2.bmp'); //soubor ma nulovou delku
>
> TempStream.Free;
> bmp.Free;
> end
>
> Libor


Odpovedá: Alexandr Stefek

15. 11. 2002 12:15

         COM/DCOM

> Kez by to rozhodujici bylo. Stale mi to neslape.
> a2.bmp ma nulovou delku. Nemusi se jeste nejak nastavit objekt bmp?

nasledujici je overene a funkcni, vice uz udelat nemohu

var
  Logo : TBitmap;
  TempStream: TMemoryStream;
  BMP : TBitmap;
begin
  Logo := TBitmap.Create;
  Logo.LoadFromFile('c:\1.bmp');
  Logo.SaveToFile('c:\1a.bmp'); //na disku ulozena bitmapa je v poradku
   //z TBitmap ulozim do streamu

  TempStream := TMemoryStream.Create;
  Logo.SaveToStream(TempStream);
  TempStream.Seek(0, soFromBeginning);

  BMP := TBitmap.Create;
  BMP.LoadFromStream(TempStream);
 //z TBitmap provedu ulozeni na disk
  BMP.SaveToFile('c:\a2.bmp');

  TempStream.Free;
  BMP.Free;
  Logo.Free;
end;

Alexandr STEFEK

Odpovedá: Libor Filip

18. 11. 2002 7:48

         COM/DCOM
Dekuji vsem, kteri mi poradili (vcetne Alexandra a Richarda)
Tady jsou funkcni metody jak dostat TBitmap pres COM

function TCOMServer.Get_Logo: OleVariant;
var
  TempStream:TMemoryStream;
  P:Pointer;
  L:Integer;
begin
  TempStream:=TMemoryStream.Create;
  try
    Logo.SaveToStream(TempStream);
    L:=TempStream.Size;
    Result:=VarArrayCreate([0,L-1], varByte);
    P:=VarArrayLock(Result);
    try
      TempStream.Seek(0, soFromBeginning);
      Move(TempStream.Memory^,P^,L);
    finally
      VarArrayUnLock(Result);
    end;
  finally
    TempStream.Free;
  end;
end;

procedure TCOMServer.Set_Logo(Value: OleVariant);
var
  P: Pointer;
  L: integer;
  TempStream:TMemoryStream;
begin
  L:=VarArrayHighBound(Value,1)-VarArrayLowBound(Value,1)+1;
  P:=VarArrayLock(Value);
  try
    TempStream:=TMemoryStream.Create;
    try
      TempStream.WriteBuffer(P^,L);
      TempStream.Seek(0, soFromBeginning);
      Logo.LoadFromStream(TempStream);
    finally
      TempStream.Free;
    end;
  finally
    VarArrayUnLock(Value);
  end;
end;



nasledujici je overene a funkcni, vice uz udelat nemohu

Alexandr STEFEK

Odpovedá: Alexandr Stefek

18. 11. 2002 14:16

         COM/DCOM
Osobne si myslim, ze je vhodnejsi to predavat pres
stream (IStream a IUnknown) ve spojeni se
TStreamAdapter a TOleStream. Podle mych osobnich
zkusenosti je to rychlejsi a zvlaste pri vetsim objemu
dat se to muze projevit vyrazneji.

Alexandr STEFEK

> Tady jsou funkcni metody jak dostat TBitmap pres COM
>
> function TCOMServer.Get_Logo: OleVariant;
> end;
>
> procedure TCOMServer.Set_Logo(Value: OleVariant);
> end;
>

Odpovedá: Ondrej Kelle

18. 11. 2002 16:48

         COM/DCOM
>> Tady jsou funkcni metody jak dostat TBitmap pres COM
>>
>> function TCOMServer.Get_Logo: OleVariant;
>> end;
>>
>> procedure TCOMServer.Set_Logo(Value: OleVariant);
>> end;

> Osobne si myslim, ze je vhodnejsi to predavat pres
> stream (IStream a IUnknown) ve spojeni se
> TStreamAdapter a TOleStream. Podle mych osobnich
> zkusenosti je to rychlejsi a zvlaste pri vetsim objemu
> dat se to muze projevit vyrazneji.

Dovolim si nesuhlasit, pretoze v tomto pripade je overhead spojeny s volanim
metod IStream zbytocny. Klient bude totiz zrejme vzdy chciet celu bitmapu,
nie len jej casti.
Kazde vzdialene volanie metody generuje prevadzku po sieti (v oboch smeroch
tam aj spet, ak vracia vysledok); z hladiska vykonu a zatazenia siete je asi
dobre obmedzit ich pocet na minimum. V tomto konkretnom pripade si myslim,
ze je vhodne riesit to jedinym volanim. Podla okolnosti by sa mozno este
hodila aj kompresia na servri a dekompresia na klientovi.

Implementacia IStream moze byt vhodnejsia v pripade, ked klient skutocne
vyzaduje funkcionalitu streamu, t.j. hlavne asi Seek kvoli
vyhladavaniu/preskakovaniu nejakych blokov dat bez nutnosti tahat vsetko na
klienta - v pripade velkych mnozstiev dat sa to moze oplatit. Ale aj v
takych pripadoch by som asi najprv uvazoval o implementacii o uroven vyssie,
ktora by to riesila inak: specializovany objekt skryvajuci format dat a
publikujuci metody vhodne pre konkretnu aplikaciu. Zavisi to samozrejme od
druhu aplikacie.

To je len moj skromny nazor; IStream som pri vzdialenych volaniach este
nepouzil, nemam s tym ziadne skusenosti, takze velmi rad sa necham poucit.

Prajem pekny Delphi den,
TOndrej